/* 
 * 	This file is part of VPN Monitor Project 7..

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package monitor.gui;

import java.util.EnumMap;
import java.util.HashMap;

import javax.swing.JProgressBar;
import javax.swing.table.AbstractTableModel;

import monitor.Monitor;
import monitor.interfaces.TrafficDataPackage;
import monitor.interfaces.TrafficPackage;
import monitor.interfaces.EnumTypes.Keys;
import monitor.interfaces.EnumTypes.Types;
import monitor.interfaces.observers.TrafficObserver;
import monitor.utility.Utility;

/**
 * Support class for the Info class, contains the data
 * for Info's JTable.
 */
@SuppressWarnings("serial")
class TrafficTable extends AbstractTableModel implements TrafficObserver{
	private static final Types[] types = Types.values();
	private static final Keys[] keys = Keys.values();
	private EnumMap<Types,EnumMap<Keys,TrafficDataPackage>> traffic = null;
	private HashMap<String,JProgressBar> progressbars = null;
	
	/**
	 * Create an instance of TrafficTable that listen for traffic updates
	 * and update traffic values accordingly. The table instance contains
	 * a complete set of Keys for every Types.
	 * 
	 * @param control For register the traffic observer.
	 */
	TrafficTable(GuiControl control){
		control.addTrafficObserver(this);
		traffic = new EnumMap<Types, EnumMap<Keys, TrafficDataPackage>>(Types.class);
		for(Types type : Types.values())
			traffic.put(type, new EnumMap<Keys, TrafficDataPackage>(Keys.class));
	}
		
	@Override
	public String getColumnName(int column){
		if(column==0)
			return "";
		else
			return types[column-1].toString();
	}
	
	@Override
	public int getColumnCount() {
		return types.length+1;
	}
	
	@Override
	public int getRowCount() {
		return keys.length;
	}

	@Override
	public Object getValueAt(int row, int column) {
		if(column==0)
			return keys[row].toString();
		if(traffic.get(types[column-1]).get(keys[row])!=null){
			TrafficDataPackage data = (traffic.get(types[column-1])).get(keys[row]);
			if(data.isLimit()){
				if(progressbars==null)
					progressbars = new HashMap<String,JProgressBar>();
				String key = types[column-1].toString() + " " + keys[row].toString();
				if(!progressbars.containsKey(key))
					progressbars.put(key, new JProgressBar());
				JProgressBar bar = progressbars.get(key);
				bar.setStringPainted(true);
				bar.setString(Utility.reportTraffic(data.getTraffic(),Monitor.TRAFFIC_REPORT_LEVEL));
				bar.setValue(progress(data.getTraffic(), data.getLimit()));
				return bar;
			} else
				return data.getTraffic();
		} else
			return "No data!";
	}
	
	/**
	 * Calculate the ratio between traffic and limit
	 * then multiply this value by 100 (traffic / limit ) * 100.
	 * This is done by first divide largest of the two input values by 10^n
	 * factor so that it's below Double.MAX_VALUE then before ratio is 
	 * calculated are both traffic and limit casted to double.
	 * 
	 * @param traffic Traffic value. 
	 * @param limit Limit value.
	 * @return Ratio multiply by 100.
	 */
	private int progress (long traffic, long limit){
		long largest = traffic >= limit ? traffic : limit;
		int divideFactor = 1;
		while(largest > Double.MAX_VALUE)
			largest /= (divideFactor*=10);
		traffic /= divideFactor;
		limit /= divideFactor;
		return (int) (((double) traffic / (double) limit)*100);
	}

	@Override
	public void trafficUpdated(TrafficPackage[] traffic) {
		for(TrafficPackage t : traffic)
			t.copyToEnumMap(this.traffic.get(t.getType()));
		this.fireTableDataChanged();
	}
}
